package com.example.demo.api;

import com.example.demo.game.*;
import com.example.demo.model.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Wukong
 * Date: 2023-04-25
 * Time: 19:57
 */
@Component
public class GameAPI extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private RoomManager roomManager;
    // 这个是管理 game 页面的会话
    @Autowired
    private OnlineUserManager onlineUserManager;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        GameReadyResponse resp = new GameReadyResponse();

        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            resp.setOk(false);
            resp.setReason("用户尚未登录!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            resp.setOk(false);
            resp.setReason("用户并未匹配成功! 不能开始游戏!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }
        System.out.println("连接游戏! roomId=" + room.getRoomId() + ", userId=" + user.getUserId());

        // 先判定用户是不是已经在游戏中了.
        if (onlineUserManager.getSessionFromGameHall(user.getUserId()) != null
                || onlineUserManager.getSessionFromGameRoom(user.getUserId()) != null) {
            resp.setOk(false);
            resp.setReason("禁止多开游戏页面!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
            return;
        }
        // 更新会话
        onlineUserManager.enterGameRoom(user.getUserId(), session);

        // 同一个房间的两个玩家, 同时连接时要考虑线程安全问题.
        synchronized (room) {
            if (room.getUser1() == null) {
                room.setUser1(user);
                // 设置 userId1 为先手方
                room.setWhiteUserId(user.getUserId());
                System.out.println("userId=" + user.getUserId() + " 玩家1准备就绪!");
                return;
            }
            if (room.getUser2() == null) {
                room.setUser2(user);
                System.out.println("userId=" + user.getUserId() + " 玩家2准备就绪!");

                // 通知玩家1 就绪
                noticeGameReady(room, room.getUser1().getUserId(), room.getUser2().getUserId());
                // 通知玩家2 就绪
                noticeGameReady(room, room.getUser2().getUserId(), room.getUser1().getUserId());
                return;
            }
        }
        // 房间已经满了!
        resp.setOk(false);
        String log = "roomId=" + room.getRoomId() + " 已经满了! 连接游戏失败!";
        resp.setReason(log);
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
        System.out.println(log);
    }
    private void noticeGameReady(Room room, int thisUserId, int thatUserId) throws IOException {
        GameReadyResponse resp = new GameReadyResponse();
        resp.setRoomId(room.getRoomId());
        resp.setThisUserId(thisUserId);
        resp.setThatUserId(thatUserId);
        resp.setWhiteUserId(room.getWhiteUserId());
        WebSocketSession session1 = onlineUserManager.getSessionFromGameRoom(thisUserId);
        session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        Room room = roomManager.getRoomByUserId(user.getUserId());
        room.putChess(message.getPayload());
    }
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        WebSocketSession existSession = onlineUserManager.getSessionFromGameRoom(user.getUserId());
        if (existSession != session) {
            System.out.println("当前的会话不是玩家游戏中的会话, 不做任何处理!");
            return;
        }
        System.out.println("连接出错! userId=" + user.getUserId());
        onlineUserManager.exitGameRoom(user.getUserId());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        User user = (User) session.getAttributes().get("user");
        if (user == null) {
            return;
        }
        WebSocketSession existSession = onlineUserManager.getSessionFromGameRoom(user.getUserId());
        if (existSession != session) {
            System.out.println("当前的会话不是玩家游戏中的会话, 不做任何处理!");
            return;
        }
        System.out.println("用户退出! userId=" + user.getUserId());
        onlineUserManager.exitGameRoom(user.getUserId());
    }

    // 通知另外一个玩家直接获胜!
    private void noticeThatUserWin(User user) throws IOException {
        Room room = roomManager.getRoomByUserId(user.getUserId());
        if (room == null) {
            System.out.println("房间已经释放, 无需通知!");
            return;
        }
        User thatUser = (user == room.getUser1() ? room.getUser2() : room.getUser1());
        WebSocketSession session = onlineUserManager.getSessionFromGameRoom(thatUser.getUserId());
        if (session == null) {
            System.out.println(thatUser.getUserId() + " 该玩家已经下线, 无需通知!");
            return;
        }
        GameResponse resp = new GameResponse();
        resp.setUserId(thatUser.getUserId());
        resp.setWinner(thatUser.getUserId());
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp)));
    }
}
